using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace StructureMap.WcfIntegration
{
    public class StructureMapServiceBehavior : IServiceBehavior
    {
        private readonly IContainer container;

        public StructureMapServiceBehavior(IContainer container)
        {
            this.container = container;
        }


        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
            {
                var cd = cdb as ChannelDispatcher;
                if (cd != null)
                {
                    foreach (EndpointDispatcher ed in cd.Endpoints)
                    {

                        ed.DispatchRuntime.InstanceProvider = new StructureMapInstanceProvider(serviceDescription.ServiceType, container);

                        //add our own cache initializer first in the chain
                        ed.DispatchRuntime.InstanceContextInitializers.Add(new InstanceContextCacheInitializer());

                        foreach (var instanceContextInitializer in container.GetAllInstances<IInstanceContextInitializer>())
                        {
                            ed.DispatchRuntime.InstanceContextInitializers.Add(instanceContextInitializer);

                        }

                        foreach (var messageInspector in container.GetAllInstances<IDispatchMessageInspector>())
                        {
                            ed.DispatchRuntime.MessageInspectors.Add(messageInspector);
                        }

                        foreach (var operation in ed.DispatchRuntime.Operations)
                        {
                            foreach (var initializer in container.GetAllInstances<ICallContextInitializer>())
                            {
                                operation.CallContextInitializers.Add(initializer);
                            }
                        }


                    }


                    //add registered error handlers
                    foreach (var errorHandler in container.GetAllInstances<IErrorHandler>())
                    {
                        cd.ErrorHandlers.Add(errorHandler);
                    }

                }
            }


        }

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {

        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }
    }
}